#define AS_SOCKET_CLIENT
#include "util.hxx"
#include "as_socket.hxx"

#include <iostream>
#include "minilog_static.hxx"
#include "modules.hxx"

#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#ifdef __cplusplus
}
#endif

AsSocketClient::AsSocketClient (void)
{
    // 连接到服务器
    m_socket = socket_connectos(socketGetaddress().c_str(), 2);
    if (INVALID_SOCKET == m_socket) {
        LogE("socket_connectos error", socketGetaddress(), ":", INT_TIMEOUT);
        exit(EXIT_FAILURE);
    }
}

// 以指定的大小发送一个socket包
static inline int socketPackageSend(socket_t s, void *data, unsigned int oriLen, unsigned int fillLen, unsigned int requireLen = 0)
{
    int ret;
    unsigned int surplus;
    struct socketPackageHead *head;


    if(oriLen >fillLen) return -1;

    head = (struct socketPackageHead *)calloc(1, fillLen + sizeof(struct socketPackageHead));

    if(!head) return -1;

    head->dataLenth = fillLen;
    head->requireLenth = requireLen;
    memcpy(head->payload, data, oriLen);
    for (surplus = oriLen; surplus < fillLen; ++surplus) {
        head->payload[surplus] = '\0';
    }

    ret = socket_sendn(s, head, fillLen + sizeof(struct socketPackageHead));
    free(head);
    return ret;
}

AsSocketClient::~AsSocketClient (void)
{
    shutdown(m_socket, SHUT_WR);
    socket_close(m_socket);
}

// 单次发送，以后单次接收
int AsSocketClient::sendRequest2ServerSingalRequest(struct moduleRequest *request)
{
    struct moduleResult moduleResult;
    int requireLen = sizeof(struct moduleResult);
    int ret;


    // CPU 切换调度的切片
    msleep(0);

    // 发送执行指令，并数据接收返回结果
    ret = socketPackageSend(m_socket,
                            request, sizeof(struct moduleRequest),
                            sizeof(struct moduleRequest), requireLen);

    if (ret == SOCKET_ERROR) {
        CERR("socket_sendn ret = %d", ret);
        goto err;
    }

    if(requireLen <= 0)
        goto end;

    ret = socket_recvn(m_socket, &moduleResult, requireLen);
    if (ret == SOCKET_ERROR) {
        CERR("socket_recvn ret = %d", ret);
        goto err;
    }
    //LogI(__FILE__, __LINE__, "socket_recvn :", data, ret);

    if(moduleResult.result == TestResultAsPass)
    {
        LogI(moduleResult.name, "ok");
        return 0;
    }else
    {
        LogE(__FILE__, __LINE__, moduleResult.name, "no");
        return -1;
    }
end:
    return 0;
err:
    socket_close(m_socket);
    exit(EXIT_FAILURE);
}

int AsSocketClient::sendRequest2ServerGetPendingData(const string & run_mode, const string & cmd)
{
    struct moduleResultData moduleResultData;
    int requireLen = sizeof(struct moduleResultData);
    struct moduleRequest request;
    int ret;

    request.type = RequestTypeGetPendingData;

    memcpy(request.name, (char*)cmd.c_str(), MODULE_NAME_MAX_SIZE);
    request.name[MODULE_NAME_MAX_SIZE - 1] = '\0';
#if 0
    request.dataSize = min(cmd.length(), MODULE_NAME_MAX_SIZE);
    memcpy(request.data, (char*)cmd.c_str(), request.dataSize);
    request.data[request.dataSize] = '\0';
#endif

    ret = socketPackageSend(m_socket,
                            &request, sizeof(struct moduleRequest),
                            sizeof(struct moduleRequest), requireLen);

    if (ret == SOCKET_ERROR) {
        CERR("socket_sendn ret = %d", ret);
        goto err;
    }

    if(requireLen <= 0)
        goto end;

    ret = socket_recvn(m_socket, &moduleResultData, requireLen);
    if (ret == SOCKET_ERROR) {
        CERR("socket_recvn ret = %d", ret);
        goto err;
    }
    // dump data
    LogD("Get module data.");
    LogD("  module: [", moduleResultData.name,"]");
    LogD("\tdata:   [", moduleResultData.data,"]");
    LogD("\tsize:   [", moduleResultData.size,"]");

end:
    return 0;
err:
    socket_close(m_socket);
    exit(EXIT_FAILURE);
}
// 成对的收发
int AsSocketClient::sendRequest2ServerGetStatusOfAllModulesWithCount(const string & run_mode, const string & cmd)
{
    struct moduleResult moduleResult;
    int requireLen = sizeof(struct moduleResult);
    struct moduleRequest request;
    struct moduleResult *requests;
    int ret, cnt, i;

    msleep(0);

    request.type = RequestTypeGetCountOfAllModules;

    memcpy(request.name, (char*)cmd.c_str(), MODULE_NAME_MAX_SIZE);
    request.name[MODULE_NAME_MAX_SIZE - 1] = '\0';
#if 0
    request.dataSize = cmd.length();
    memcpy(request.data, (char*)cmd.c_str(), request.dataSize);
#endif

    // 获取 模块数量
    ret = socketPackageSend(m_socket,
                            &request, sizeof(struct moduleRequest),
                            sizeof(struct moduleRequest), requireLen);

    if (ret == SOCKET_ERROR) {
        CERR("socket_sendn ret = %d", ret);
        goto err;
    }

    if(requireLen <= 0)
        goto end;

    ret = socket_recvn(m_socket, &moduleResult, requireLen);
    if (ret == SOCKET_ERROR) {
        CERR("socket_recvn ret = %d", ret);
        goto err;
    }
    // 根据数量申请对应的空间
    cnt = moduleResult.result;
    requireLen = cnt * (sizeof(struct moduleResult));
    requests = new struct moduleResult[cnt];
    request.type = RequestTypeGetStatusOfAllModulesWithCount;
    // 获取 模块数量
    ret = socketPackageSend(m_socket,
                            &request, sizeof(struct moduleRequest),
                            sizeof(struct moduleRequest), requireLen);
    ret = socket_recvn(m_socket, requests, requireLen);
    for (i = 0; i < cnt; ++i) {
        LogI(requests[i].name, requests[i].result);
    }

    delete []requests;

end:
    return 0;
err:
    socket_close(m_socket);
    exit(EXIT_FAILURE);
}

int AsSocketClient::sendRequest2Server(const string & run_mode, const string & cmd, const string & set_value)
{
    struct moduleRequest request;
    int ret;
    ret = strs2moduleRequest(run_mode, cmd, set_value, &request);
    if(ret)
        return -1;

    // 根据运行模式和命令，构造请求包
    LogD(__FILE__, __LINE__, "cmd", cmd);
    LogD(__FILE__, __LINE__, "mode", run_mode);

    switch(request.type)
    {
        case RequestTypeGetCommandResult:
        case RequestTypeSetCommandResult:
        case RequestTypeRunCommand:
        case RequestTypeGetCountOfAllModules:
            return sendRequest2ServerSingalRequest(&request);
        case RequestTypeGetPendingData:
            return sendRequest2ServerGetPendingData(run_mode, cmd);

        case RequestTypeGetStatusOfAllModulesWithCount:
            return sendRequest2ServerGetStatusOfAllModulesWithCount(run_mode, cmd);
        default:
            return -1;
    }
}
